/*
Copyright (C) 2015 Marien Raat

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

#include <vector>

struct Vec3f {
    float x;
    float y;
    float z;
};

struct Light {
    // The color of the light. The colors are saved in (x, y, z) ->
    // (r, g, b). The basic strength of the light is implicited in the
    // lightness of this color.
    Vec3f color;
    // The falloff of the strength of the light that occurs when a
    // point is farther from this light. The total light strenth of a
    // light is calculated by multiplying the total falloff with the
    // color of the light.
    // The total falloff is calculated with:
    //    total_falloff = falloff.x * pow(distance, 1) +
    //                    falloff.y * pow(distance, 2) +
    //                    falloff.z * pow(distance, 3);
    Vec3f falloff;
    // The position of the light relative to the top left corner of
    // the map.
    Vec3f position;
};

// LigthingGenerator can generate a normal map based on a given
// heightmap. It can then generate a lighting map based on this
// normal map and a vector of Lights.
class LightingGenerator {
public:
    LightingGenerator();
    // Generates a normal map from a heightmap and puts it in
    // this->normalmap
    void generateNormalMap(
        // The heightmap to generate a normal map from
        double *heightmap,
        // The width and the height of the heightmap (and thus the
        // generated normal map)
        int width,
        int height,
        // Whether to overwrite the old normal map
        bool overwriteOldMap = true
        );

    // Generates a lighting map based on this->normalmap and a vector
    // of lights.
    // This function doesn't take the actual height of the points on
    // the map in regard, since lights are usually to far away for
    // this to have any impact.
    // This function will not generate a light if this->normalmap is
    // not initialized (when this->generateNormalmap has not been
    // called).
    void generateLightMap(
        // A vector of the lights used to light the heightmap
        std::vector<Light> lights,
        // The diffuse light value. All pixels will get at least this
        // light
        Vec3f diffuse,
        // Whether to overwrite the old light map
        bool overwriteOldMap = true
        );
    Vec3f *normalmap;
    Vec3f *lightmap;
private:
    int currentMapWidth, currentMapHeight;
    int previousLightmapWidth, previousLightmapHeight;
    bool firstNormalMap, firstLightMap;
    Vec3f getNormal(int x, int y, double *heightmap);
    float getDotProduct(int x, int y, Light light);
};
